///
//  Sprite v 1.0
//  Russell Lowke, Febrauary 26th 2011
//
//  Copyright (c) 2011 Lowke Media
//  see http://www.lowkemedia.com for more information
//
//  Permission is hereby granted, free of charge, to any person obtaining a 
//  copy of this software and associated documentation files (the "Software"), 
//  to deal in the Software without restriction, including without limitation 
//  the rights to use, copy, modify, merge, publish, distribute, sublicense, 
//  and/or sell copies of the Software, and to permit persons to whom the 
//  Software is furnished to do so, subject to the following conditions:
// 
//  The above copyright notice and this permission notice shall be included in 
//  all copies or substantial portions of the Software.
// 
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
//  IN THE SOFTWARE. 
//
//

function Sprite()
{   
    this.visible = true;                            // (boolean) if false sprite is not drawn on update()
    this.parent;                                    // (Sprite) parent object for this Sprite
    this.x = 0;                                     // (number) x location
    this.y = 0;                                     // (number) y location
    this.width = 0;                                 // (number) width of Sprite, usually set by extending class
    this.height = 0;                                // (number) height of Sprite, usually set by extending class
    this.regX = 0;                                  // (number) registration x location, around which Sprite scales and rotates
    this.regY = 0;                                  // (number) registration y location, around which Sprite scales and rotates
    this.alpha = 1;                                 // (number) alpha transparency, 1 = opaque, 0 = transparent
    this.rotation = 0;                              // (number) in degrees, 0 to 360
    this.scaleX = 1;                                // (number) scale in x, 1 = 100%
    this.scaleY = 1;                                // (number) scale in y, 1 = 100%
    this.children;                                  // (Array) display list of children Sprites attached to this Sprite
    
    this.update = function(ctx)                     // (context) canvas context being drawn into
    {
        // if Sprite not visible exit the update
        if (! this.visible) {
            return;
        }
        
        ctx.save();
        
        // translate x and y
        ctx.translate(this.x, this.y);
            
        // handle alpha
        if (this.alpha !== 1) {
            ctx.globalAlpha = this.alpha;
        }
            
        // handle scale
        if (this.scaleX !== 1 || this.scaleY !== 1) {
            ctx.scale(this.scaleX, this.scaleY);
        }
            
        // handle rotation
        if (this.rotation) {
            ctx.rotate(Sprite.degreesToRadians(this.rotation));     // KEEP this.rotation in radians ??
        }
        
        // draw sprite content
        this.draw(ctx);
        
        // update Sprite children on the display list
        if (this.children) {
            for (var i = 0; i < this.children.length; ++i) {
                this.children[i].update(ctx);
            }
        }
        
        ctx.restore();
    };
    
    ///
    // draw function for override by extending classes
    //
    this.draw = function(ctx)               // (context) canvas context being drawn into
    {
        // Sprite is extended for draw function
        //   A Sprite alone is a container and has nothing to draw
    }
    
    ///
    // Adds a child to the top of the display list. 
    // Returns the child that was added.
    //
    this.addChild = function(child)         // (Sprite) sprite to be added to displayList
    {
        if (! this.children) {
            this.children = new Array();
        }
        if (child.parent) {
            child.parent.removeChild(child);
        }
        child.parent = this;
        this.children.push(child);
        return child;
    }   
    
    ///
    // Adds a child to the display list at the specified index, bumping children at equal or greater indexes up one.
    // The index must be between 0 and numChildren. 
    // Returns the child that was added.
    //
    this.addChildAt = function(child,       // (Sprite) child to be added to displayList
                               index)       // (uint) index to add the child at
    {
        if (child.parent) { 
            child.parent.removeChild(child); 
        }
        child.parent = this;
        this.children.splice(index, 0, child);
        return child;
    }
    
    
    ///
    // Removes the specified child from the display list. 
    // Note that it is faster to use removeChildAt() if the index is already known. 
    // Returns true if the child was removed, or false if it was not in the display list.
    //
    this.removeChild = function(child)      // (Sprite) child to be removed from displayList
    {
        return this.removeChildAt(this.children.indexOf(child));
    }
    
    ///
    // Removes the child at the specified index from the display list, and sets its parent to null. 
    // Returns true if the child was removed, or false if the index was out of range.
    //
    this.removeChildAt = function(index)    // (uint) index of child to remove
    {
        if (index < 0 || index > this.children.length - 1) { 
            return false; 
        }
        var child = this.children[index];
        child.parent = undefined;
        this.children.splice(index, 1);
        return true;
    }
    
    ///
    // Removes all children from the display list.
    //
    this.removeAllChildren = function() 
    {
        while (this.children.length) { 
            this.removeChildAt(0); 
        }
    }
    
    ///
    // convenience function for setting regX and regY
    //
    this.setReg = function(align) {         // (string) alignment setting, typically Sprite.CENTER
        
        switch (align) {
            case Sprite.TOP_LEFT:       this.regX = 0;              this.regY = 0;              return;
            case Sprite.TOP_CENTER:     this.regX = this.width/2;   this.regY = 0;              return;
            case Sprite.TOP_RIGHT:      this.regX = this.width;     this.regY = 0;              return;
            case Sprite.MID_LEFT:       this.regX = 0;              this.regY = this.height/2;  return;
            case Sprite.CENTER:         this.regX = this.width/2;   this.regY = this.height/2;  return;
            case Sprite.MID_RIGHT:      this.regX = this.width;     this.regY = this.height/2;  return;
            case Sprite.BOTTOM_LEFT:    this.regX = 0;              this.regY = this.height;    return;
            case Sprite.BOTTOM_CENTER:  this.regX = this.width/2;   this.regY = this.height;    return;
            case Sprite.BOTTOM_RIGHT:   this.regX = this.width;     this.regY = this.height;    return;
        }
        
        throw new Error("setReg() can't understand align parameter of \"" + align + "\"");
    }
    
    ///
    // convenience function that sets both scaleX and scaleY
    //
    this.setScale = function(scale) {       // (number) percentage scale to draw
        this.scaleX = scale;
        this.scaleY = scale;
    }
}

//
// static helper functions


///
// Convert radians to degrees.
// degrees = radians*180/PI
//
Sprite.radiansToDegrees = function(degrees) {
    // precalculate 180/PI = 57.295779513082289
    return degrees*57.295779513082289;
}
    
///
// Convert degrees to radians.
// radians = degrees*PI/180
//
Sprite.degreesToRadians = function(degrees) {
    // precalculate PI/180 = 0.01745329251994
    return degrees*0.01745329251994;
}
    
    
// align constants for setReg() method
Sprite.TOP_LEFT         = "top left";
Sprite.TOP_CENTER       = "top center";
Sprite.TOP_RIGHT        = "top right";
Sprite.MID_LEFT         = "mid left";
Sprite.CENTER           = "center";
Sprite.MID_RIGHT        = "mid right";
Sprite.BOTTOM_LEFT      = "bottom left";
Sprite.BOTTOM_CENTER    = "bottom center";
Sprite.BOTTOM_RIGHT     = "bottom right";

    
    /*
    
    // ADD this.shadow parameter?
    // 

    /*
    p.applyShadow = function(ctx, shadow) {
        ctx.shadowColor = shadow.color;
        ctx.shadowOffsetX = shadow.offsetX;
        ctx.shadowOffsetY = shadow.offsetY;
        ctx.shadowBlur = shadow.blur;
    }
     */ 
     /*

    p.toString = function() {
        return "[Container (name="+  this.name +")]";
    }
    
    p.toString = function() {
        return "[DisplayObject (name="+  this.name +")]";
    }
    */
